#pragma once
#include"Thread.hpp"
#include"LockGuard.hpp"
#include"log.hpp"
#include<vector>
#include<queue>
#include<mutex>
#include<unistd.h>


const int gnum=10;

template<class T>
class ThreadPool;

template<class T>
class ThreadData
{
public:
    ThreadPool<T> *_tppoint;
    string _name;

    ThreadData(ThreadPool<T>* tp,const string& name):_tppoint(tp),_name(name)
    {}
};


template<class T>
class ThreadPool
{
public:
    static void* handlerTask(void* args)
    {
        ThreadData<T>* td = static_cast<ThreadData<T>*>(args);
        while(true)
        {
            T t;
            {
                LockGuard lockguard(td->_tppoint->getmutex());
                while(td->_tppoint->isQueueEmpty())
                {
                    td->_tppoint->threadWait();
                }
                t  = td->_tppoint->pop();
            }
            t();
        }
        delete td;
        return nullptr;
    }

    ThreadPool(const int num = gnum):_num(num)
    {
        pthread_mutex_init(&_mutex,nullptr);
        pthread_cond_init(&_cond,nullptr);
        for(int i=0;i<_num;i++)
            _threads.push_back(new Thread());
    }

    void lockQueue() {pthread_mutex_lock(&_mutex);}
    void unlockQueue() {pthread_mutex_unlock(&_mutex);}
    bool isQueueEmpty() {return _task_queue.empty();}
    void threadWait() {pthread_cond_wait(&_cond,&_mutex);}
    pthread_mutex_t* getmutex(){return &_mutex;}

    T pop()
    {
        T t = _task_queue.front();
        _task_queue.pop();
        return t;
    }

    void push(const T& in)
    {
        LockGuard lockguard(&_mutex);
        _task_queue.push(in);
        pthread_cond_signal(&_cond);
    }

    void run()
    {
        for(const auto& t:_threads)
        {
            ThreadData<T> *td = new ThreadData<T>(this,t->getName());
            t->start(handlerTask,td);
            logMessage(DEBUG,"%s start ...",t->getName().c_str());
        }
    }

    ~ThreadPool()
    {
        pthread_mutex_destroy(&_mutex);
        pthread_cond_destroy(&_cond);
        for(const auto& t:_threads) delete t;
    }

private:
    int _num;
    vector<Thread*> _threads;
    queue<T> _task_queue;
    pthread_mutex_t _mutex;
    pthread_cond_t _cond;

};





